package asteroids.model;
import asteroids.CollisionListener;
import asteroids.Util;
import be.kuleuven.cs.som.annotate.*;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import be.kuleuven.cs.som.annotate.Basic;

/**
 * 
 * @invar	 This world contains proper Entities.
 * 			| hasProperEntities()
 * @invar	This world has valid dimensions.
 * 			| isValidDimension(getWidth()) && isValidDimension(getHeight())
 * 
 * @version 0.3
 * @author  Tandan Sunil, Van Deun Luca
 *
 */
public class World {
	private Set<Entity> entities;
	private final double height;
	private final double width;
	public static final double MAX_DIMENSION = Double.MAX_VALUE;
	
	/**
	 * Create a new World with given height and width. 
	 * @param height
	 * 		  The height of this new world.
	 * @param width
	 * 		  The width of this new world.
	 * @throws IllegalArgumentException
	 * 		  |!isValidDimension(height) || !isValidDimension(width)
	 */	
	public World(double height,double width) throws IllegalArgumentException{
		if(!isValidDimension(height) || !isValidDimension(width))
			throw new IllegalArgumentException("Illegal world dimension");
		this.height = height;
		this.width = width;
		entities = new HashSet<Entity>();
		
	}

	/**
	 * Checks whether the given dimension is valid.
	 * @param dimension
	 * 			The dimension to be checked.
	 * @return	...
	 * 		|	result == (!Double.isNaN(dimension) && dimension >= 0 || dimension <= MAX_DIMENSION)
	 * 
	 */
	public static boolean isValidDimension(Double dimension){
		if(Double.isNaN(dimension) || dimension < 0 || dimension > MAX_DIMENSION)
			return false;
		return true;
	}
	
	/**
	 * Returns the ships situated in this world.
	 */
	@Basic
	public Set<Ship> getShips() {
		Set<Ship> ships = new HashSet<Ship>();
		for(Entity entity : entities){
			if(Ship.class.isInstance(entity)){
				ships.add((Ship)entity);
			}
		}
		return new HashSet<Ship>(ships);
	}
	
	/**
	 * Returns the asteroids situated in this world.
	 */
	@Basic
	public Set<Asteroid> getAsteroids() {
		Set<Asteroid> asteroids = new HashSet<Asteroid>();
		for(Entity entity : entities){
			if(Asteroid.class.isInstance(entity)){
				asteroids.add((Asteroid)entity);
			}
		}
		return new HashSet<Asteroid>(asteroids);
	}
	
	/**
	 * Returns the bullets situated in this world.
	 */
	@Basic
	public Set<Bullet> getBullets() {
		Set<Bullet> bullets = new HashSet<Bullet>();
		for(Entity entity : entities){
			if(Bullet.class.isInstance(entity)){
				bullets.add((Bullet)entity);
			}
		}
		return new HashSet<Bullet>(bullets);
	}
	
	/**
	 * Returns the height of this world.
	 */
	@Basic
	public double getHeight() {
		return height;
	}
	
	/**
	 * Returns the width of this world.
	 */
	@Basic
	public double getWidth() {
		return width;
	}
	/**
	 * Returns the entities situated in this world.
	 */
	@Basic
	public Set<Entity> getAllEntities(){
		return new HashSet<Entity>(entities);
		}
	
	
	/**
	 * Returns true if this world contains the given entity.
	 * @param 	entity
	 * 			The entity to be checked.
	 * @return
	 * 		  | result == (getEntities().contains(entity))       
	 */
	public boolean contains(Entity entity){
		if(entities.contains(entity))
			return true;
		return false;
	}
	

	/**
	 * Check whether this world is terminated.
	 */
	@Basic
	public boolean isTerminated() {
		return this.isTerminated;
	}

	/**
	 * Terminate this world.
	 *
	 * @post    This world is terminated.
	 *        | new.isTerminated()
	 * @post    Each of the entities of this world no longer has
	 *          a world.
	 *        | for each entity in getAllEntities():
	 *        |	  (! (new entity).hasOwner())
	 */
	public void terminate() {
		if (!isTerminated()) {
			for (Entity entity : getAllEntities())
				entity.unsetWorld();
			this.isTerminated = true;
		}
	}

	/**
	 * Variable reflecting whether or not this world is terminated.
	 */
	private boolean isTerminated;



	/**
	 * Return the number of entities of this world.
	 */
	@Basic
	public int getNbEntities() {
		return entities.size();
	}

	/**
	 * Check whether this world can have the given entity
	 * as one of its entities.
	 * 
	 * @param   entity
	 *          The entity to check.
	 * @return  True if and only if the given entity is effective, and
	 *          if that entity can have this world as its world.
	 *        | result ==
	 *        |   (entity != null) &&
	 *        |   entity.canHaveAsWorld(this)
	 */
	public boolean canHaveAsEntity(Entity entity) {
		return (entity != null) && entity.canHaveAsWorld(this);
	}


	/**
	 * Check whether this world has a proper list of entities.
	 * 
	 * @return  True if and only if this world can have each of its
	 *          entities, and if each of these entities
	 *          references this world as their world.
	 *        | let entities = new ArrayList\<Entity\>(getAllEntities())
	 *        | for each entity in entities
	 *        |   canHaveAsEntity(entity) &&
	 *        |   entity.getWorld() == this && 
	 *        |   (entities.indexOf(entity)== entities.lastIndexOf(entity)) &&
	 *        |  isInsideBounds(entity)
	 */
	public boolean hasProperEntities() {
		ArrayList<Entity> entities = new ArrayList<Entity>(getAllEntities());
		for(Entity entity: entities){
				if(!canHaveAsEntity(entity) || (entity.getWorld()!=this) || !isInsideBounds(entity) || entities.indexOf(entity)!= entities.lastIndexOf(entity))
					return false;
		}
		return true;
	}

	/**
	 * Add the given entity as an entity of this world.
	 * 
	 * @param   entity
	 *          The entity to be added.
	 * @pre     The given entity is effective.
	 *        | (entity != null)
	 * @pre     This world does not not yet have the given entity
	 *          as one of its entities.
	 *        | ! contains(entity)
	 * @post	...
	 * 		  | if(
	 * 		  |(for each ent in getAllEntities(): !(entity.overlap(ent)))&& isInsideBounds(entity))
	 * 		  | 	new.contains(entity) && entity.getWorld() == this
	 * @effect	...
	 * 		  |if(entity instanceof Bullet && for each ent in getAllEntities(): (entity.overlap(ent)))
	 * 		  |  then entities.add(entity) 
	 * 		  |       entity.setWorldTo(this)
	 * 		  |       entity.collide(ent,null)
	 */
	public void addAsEntity(@Raw Entity entity) {
		assert (entity != null&& !contains(entity));
		Entity overlapingEntity =null;
		boolean overlap = false;
		for(Entity e: entities){
			if(e.overlap(entity)){
				overlap=true;
				overlapingEntity =e;
			}
			
		}
		
		if(!overlap && isInsideBounds(entity)){			
			entities.add(entity);
			entity.setWorldTo(this);
			//stateChanged(entity);
		}
		if((overlap && isInsideBounds(entity)) && (entity instanceof Bullet)){
			entities.add(entity);
			entity.setWorldTo(this);
			overlapingEntity.collide(entity, null);
		
		}
		
	}
	
	/**
	 * Checks if the entity is inside bound of this world. 
	 * @param 	entity
	 * 			| The entity to be checked.
	 * @return	...
	 * 			| result != (entity.getXCoordinate() < entity.getRadius() || entity.getYCoordinate() < entity.getRadius())
	 * 			| || (entity.getXCoordinate()+entity.getRadius() > getWidth()) || (entity.getYCoordinate()+entity.getRadius() > getHeight())
	 */
	public boolean isInsideBounds(Entity entity){
		if(entity.getXCoordinate() < entity.getRadius() || entity.getYCoordinate() < entity.getRadius()){
			return false;
		}
		if((entity.getXCoordinate()+entity.getRadius() > getWidth()) || (entity.getYCoordinate()+entity.getRadius() > getHeight()))
			return false;
		return true;
	}

	/**
	 * Remove the given entity from the entities of this world.
	 * 
	 * @param   entity
	 *          The entity to be removed.
	 * @pre     The given entity is effective and has no effective world.
	 *        | (entity != null) && (entity.getWorld() == null)
	 * @pre     This world has the given entity as one of
	 *          its entities.
	 *        | contains(entity)
	 * @post    The number of entities of this world is decremented
	 *          by 1.
	 *        | new.getNbEntities() == getNbEntities() - 1
	 * @post    This world no longer has the given entity as
	 *          one of its entities.
	 *        | (! new.contains(entity))
	 */
	@Raw
	public void removeAsEntity(Entity entity) {
		assert (entity != null) && (entity.getWorld() == null);
		assert (contains(entity));
		entities.remove(entity);
		//removeFutureEventOf(entity);
	}
	
	/**
	 * Moves all the entities in this world with the given time dt and
	 * resolves all collision events taking place within this timeframe,
	 * while executing ship's program when necessary.
	 * 
	 * @param dt
	 * 		  The in which the entities in this world will move.
	 * @param collisionListener
	 * 		  The collision listener to be called when a collision occurs.
	 * @post  ...
	 * 		  | new.getTimePassedAfterProgramExectution() == (getTimePassedAfterProgramExecution() +  dt) % getTimeToExecuteProgram()
	 * @effect ...
	 * 		  | if(getTimePassedAfterProgramExecution() + dt < getTimeToExecuteProgram()) 
	 * 		  | then
	 * 		  | 	let events be getFirstEvents(dt)
	 * 		  | 	if(events.isEmpty())
	 * 		  |			then for each entity in getAllEntities(): entity.move(dt)
	 * 		  |          
	 * 		  | 	else {
	 * 		  |     	let collisionTime be events.get(0).getTime()
	 * 		  |     	for each entity in getAllEntities(): entity.move(collisionTime)		
	 * 		  |     	for each event in events: event.resolve(collisionListener)
	 * 		  |     	if((dt - colllisionTime) > 0)) 
	 * 		  |         	then evolve((dt-collisionTime),collisionListener 
	 * 		  |          }
	 * 		  | else {
	 * 		  |     setTimePassedAfterProgramExecution(this,0);
	 * 		  |     evolve((getTimeToExecuteProgram() - getTimePassedAfterProgramExecution()/2),collisionListener )
	 * 		  |     setTimePassedAfterProgramExecution(this,0);
	 * 		  |     evolve((getTimeToExecuteProgram() - getTimePassedAfterProgramExecution()/2),collisionListener )
	 * 		  |     setTimePassedAfterProgramExecution(this,0);
	 * 		  |     for each ship in getShips(): ship.executeProgram()
	 * 		  |     if((dt - (getTimeToExecuteProgram() - getTimePassedAfterProgramExecution())) > 0) 
	 * 		  |     	then evolve((dt - (getTimeToExecuteProgram() - getTimePassedAfterProgramExecution()),collisionListener) 
	 * 		  |      }
	 */		
	public void evolve(double dt, CollisionListener collisionListener){
		if(getTimePassedAfterProgramExecution()+dt < getTimeToExecuteProgram()){
			ArrayList<Event> events = getFirstEvents(dt);
			if(!events.isEmpty()){
				double tc = events.get(0).getTime();
				for(Entity entity: getAllEntities()){
					entity.move(tc);
				}
				setTimePassedAfterProgramExecution(this,getTimePassedAfterProgramExecution()+tc);
				for(Event event:events){
					event.resolve(collisionListener);
				}
				
				dt = dt-tc;
				if(dt > 0){
				evolve(dt, collisionListener);}
			}
			else{
				for(Entity entity: getAllEntities()){
					entity.move(dt);					
					}
				setTimePassedAfterProgramExecution(this,getTimePassedAfterProgramExecution()+dt);
			}
		}
		
		else{
			// timepasse = 0.19 dt = 0.02
				double timeUntilNextEvolve = (getTimeToExecuteProgram() - (getTimePassedAfterProgramExecution())); //timeUn = 0.01    
				setTimePassedAfterProgramExecution(this,0);
				evolve(timeUntilNextEvolve/2, collisionListener); // evolve(0.01)
				setTimePassedAfterProgramExecution(this,0);
				evolve(timeUntilNextEvolve/2, collisionListener); // evolve(0.01)
				setTimePassedAfterProgramExecution(this,0);
				dt -= timeUntilNextEvolve;   // dt = 0.01
				for(Ship ship: getShips())
						ship.executeProgram();
				if(dt > 0)
				evolve(dt, collisionListener);  //evolve met 0.01
			
		}
	}
	private double timePassedAfterProgramExecution =0;
	/**
	 * Returns the time passed after last program execution.
	 */
	@Basic
	public double getTimePassedAfterProgramExecution(){
		return timePassedAfterProgramExecution;
	}
	/**
	 * Sets the time passed after program execution.
	 * @param world
	 * 			The world that calls this method.
	 * @param time
	 * 			The time to be set.
	 * @post  ...
	 * 			| if(world == this && !Double.isInfinite(time) && !Double.isNaN(time) && time >=0)
	 *			|	then geTimePassedAfterProgramExecution() == time
	 */
	public void setTimePassedAfterProgramExecution(World world, double time){
		if(world == this && !Double.isInfinite(time) && !Double.isNaN(time) && time >=0)
			timePassedAfterProgramExecution = time;
	}
//	private ArrayList<Event> futureEvents;
//	private void calculateFutureEvents(){
//		ArrayList<Entity> entities = new ArrayList<Entity>(getAllEntities());
//		ArrayList<Event> events = new ArrayList<Event>();
//		for(int i = 0; i<entities.size();i++){
//			Entity entity = entities.get(i);
//			for(int index = i+1; index<entities.size();index++){
//				Entity entity1 = entities.get(index);
//				if(entity1 instanceof Bullet && entity instanceof Bullet){
//					if(((Bullet)entity1).getSource() != ((Bullet)entity).getSource()){
//						double time = Collision.getTimeToCollision(entity, entity1);
//						if(!Double.isInfinite(time)){
//							Event temp = new Event(entity,entity1,time);
//							if(events.isEmpty()){
//							events.add(temp);
//							}
//							for(int ind = 0;ind < events.size();ind++){
//								if(events.get(ind).getTime() >= time){
//									events.add(ind,temp);
//									break;
//								}
//								
//							}
//						}
//												
//					}
//					
//				}
//				else{
//					double time = Collision.getTimeToCollision(entity, entity1);
//					if(!Double.isInfinite(time)){
//						Event temp = new Event(entity,entity1,time);
//						if(events.isEmpty()){
//						events.add(temp);
//						}
//						for(int ind = 0;ind < events.size();ind++){
//							if(events.get(ind).getTime() >= time){
//								events.add(ind,temp);
//								break;
//							}
//							
//						}
//						}
//				
//					}
//				}
//			double boundaryColTime = Collision.getTimeToBoundaryCollision(entity);
//			
//			if(!Double.isInfinite(boundaryColTime)){
//				Event temp = new Event(entity,null,boundaryColTime);
//				if(events.isEmpty()){
//				events.add(temp);
//				}
//				for(int ind = 0;ind < events.size();ind++){
//					if(events.get(ind).getTime() >= boundaryColTime){
//						events.add(ind,temp);
//						break;
//					}
//					
//				}
//			}			
//			
//		}
//		
//	}
//	
	
	/**
	 * Returns the first events taking place at the same time within the given time dt. 
	 * 
	 * @param dt
	 * 		  The given time in which Events can take place.
	 * @return Each Event i in result has the same i.getTime() in which this Event will take place.
	 * 		 | for each index in 0..result.size()-1 :
	 * 		 | 	for each i in index+1..result.size()-1:
	 * 		 | 	    Util.fuzzyEquals(result.get(index).getTime(),result.get(i).getTime()) 
	 * @return Returns the first collision Events to take place in a given time dt. 
	 * 		   Returns an empty List if no collision Events take place during the given time dt.
	 * 		 | let collisionTime be result.get(0).getTime() and 
	 * 		 |	   allEntities be getAllEntities()
	 *   	 | for each time in 0..collisionTime:
	 * 		 | 	for each entity in allEntities: entity.move(time)
	 * 		 | 	for each index in 0..allEntities.size()-1:
	 * 		 | 		isInsideBounds(allEntities.get(index))
	 * 		 | 		for each i in index+1..allEntities.size()-1:
	 * 		 |          let entity be allEntities.get(index) 
	 * 		 |				and entity1 be allEntities.get(i)
	 * 		 |			if(entity instanceof Bullet && entity1 instanceof Ship)
	 * 		 |					if(((Bullet)entity).getSource()!=entity1): !(entity.overlap(entity1))
	 * 		 | 	  		else if (entity instanceof Ship && entity1 instanceof Bullet)
	 * 		 |					if(((Bullet)entity1.getSource()!=entity) : !(entity.overlap(entity1))
	 *		 |          else if(entity instanceof Bullet && entity1 instanceof Bullet)
	 *		 |					if(((Bullet)entity).getSource()!=((Bullet)entity1).getSource()) : !(entity.overlap(entity1))
	 *		 |			else
	 *		 |                !(entity.overlap(entity1))
	 * 		 |
	 * @return The entities in each event of result are not related.
	 * 		 |  for each event in result:
	 * 		 | 		if(event.getEntity2!=null){
	 * 		 |			!event.getEntity1().isRelated(event.getEntity2())		
	 * 		 |		}
	 */
	public ArrayList<Event> getFirstEvents(double dt){
		ArrayList<Entity> entities = new ArrayList<Entity>(getAllEntities());
		double tc = Double.POSITIVE_INFINITY;
		double boundaryColTime = Double.POSITIVE_INFINITY;
		ArrayList<Event> events = new ArrayList<Event>();
		for(int i = 0; i<entities.size();i++){
			Entity entity = entities.get(i);
			for(int index = i+1; index<entities.size();index++){
				Entity entity1 = entities.get(index);
				if(!entity.isRelated(entity1)){
					double time = entity.getTimeToCollision(entity1);
					if(!Double.isInfinite(time) && Util.fuzzyEquals(time, tc)){
						events.add(new Event(entity,entity1,time));
					}
					if(time < tc && time >= 0 && time < dt){
						events.clear();
						events.add(new Event(entity,entity1,time));		
						tc = time;
					}
				}
				}
			boundaryColTime = entity.getTimeToBoundaryCollision();
			
			if(!Double.isInfinite(boundaryColTime) && Util.fuzzyEquals(boundaryColTime, tc)){
				events.add(new Event(entity,boundaryColTime));
			}
			if(boundaryColTime < tc && boundaryColTime >= 0 && boundaryColTime < dt){
				events.clear();
				events.add(new Event(entity,boundaryColTime));		
				tc = boundaryColTime;
			}
		}
		return events;
	}
	
	/**
	 * Checks whether the given world is valid.
	 * @param 	 world
	 * 			| The world to be checked.
	 * @return	...
	 * 			|result == (world == null || !world.isTerminated())
	 */
	public static boolean isValidWorld(World world){
		return (world == null || !world.isTerminated());
	}
	
	/**
	 * Returns the total number of bullets of the given ship in this world.
	 * @param ship
	 * 		  | The ship whose bullets has to be counted.
	 */
	@Basic
	public int getNbOfBullets(Ship ship){
		int totalbullets = 0;
		for(Bullet bullet : getBullets()){
			if(bullet.getSource()==ship)
				totalbullets++;
		}
		return totalbullets;
	}
	
	private final double timeToExecuteProgram = 0.2;
	/**
	 * Returns the time in which the next action statement of the program is executed.
	 * 
	 */
	@Basic
	public double getTimeToExecuteProgram(){
		return timeToExecuteProgram;
	}
	
	
	//////////////////////////////////Extra deel 2//////////////////////////////
//	public ArrayList<Event> futureEvents= new ArrayList<Event>();
//	public ArrayList<Event> getFutureEvents(){
//		return new ArrayList<Event>(futureEvents);
//	}
//	public void addFutureEvents(Event event){
//		int index = Integer.MAX_VALUE;
//		for(Event e: getFutureEvents()){
//			if(event.getTime()<=e.getTime()){
//				index = getFutureEvents().indexOf(e);
//				break;
//			}
//		}
//		if(index != Integer.MAX_VALUE){
//			futureEvents.add(index, event);
//		}
//		else{
//			futureEvents.add(event);
//		}
//	}
//	public void removeFutureEventOf(Entity entity){
//		ArrayList<Event> toRemoveEvents = new ArrayList<Event>();
//		ArrayList<Entity> stateChangedObjects = new ArrayList<Entity>();
//		for(Event e: getFutureEvents()){
//			if(e.contains(entity)){
//				toRemoveEvents.add(e);
//			}
//			if(e.getEntity1()!=entity)
//				stateChangedObjects.add(e.getEntity1());
//			
//		}
//		for(Event e: toRemoveEvents){
//			removeFutureEvent(e);
//		}
//		for(Entity e: stateChangedObjects){
//			stateChanged(e);
//		}
//	}
//	
//		
//	public boolean containsFutureEventOf(Entity entity){
//		for(Event event: getFutureEvents()){
//			if(event.contains(entity) && event.getEntity1()==entity) return true;
//		}
//		return false;
//	}
//	public void removeFutureEvent(Event event){
//		futureEvents.remove(event);
//	}
//	
//	public void stateChanged(Entity entity){
//		removeFutureEventOf(entity);
//		for(Event e:getFirstEventsOf(entity)){
//			addFutureEvents(e);
//		}
//	}
//	public void reduceFutureEventTime(double dt){
//		for(Event e: getFutureEvents()){
//			e.setTime(e.getTime()-dt);
//		}
//	}
//	
//	private double evolvedTime=0;
//	public double getEvolvedTime(){
//		return evolvedTime;
//	}
//	public void addEvolvedTime(double dt){
//		evolvedTime+=dt;
//	}
//	public void evolve(double dt, CollisionListener collisionListener){
//		ArrayList<Event> events = new ArrayList<Event>();
//		ArrayList<Event> futureEvents = getFutureEvents();
//		
//		
//		double firstEventTime = futureEvents.get(0).getTime();
//		
//		if(firstEventTime<0){
//			System.out.println("negative firsttimevent"+firstEventTime);
//		}
//		else{
//			System.out.println("positive firsttimevent"+firstEventTime);
//		}
//		for(int index= 0; index <futureEvents.size();index++){
//			if(Util.fuzzyEquals(futureEvents.get(index).getTime(),firstEventTime)){
//				events.add(futureEvents.get(index));
//				
//			}
//			else
//				break;
//		}	
//		if(!events.isEmpty() && firstEventTime <= dt+getEvolvedTime()){
//			ArrayList<Entity> stateChangedObjects= new ArrayList<Entity>();
//			for(Entity entity: getAllEntities()){
//				entity.move(firstEventTime);
//				if(entity instanceof Ship && ((Ship) entity).isShipThrusterActive()){
//					stateChangedObjects.add(entity);
//				}
//				
//			}
//			addEvolvedTime(firstEventTime);
//			
//			System.out.println("Entity0-1:"+ events.get(0).getEntity1());
//			try{
//			System.out.println("Entity0-2:"+ events.get(0).getEntity2()+"\n WorldContainsThis:" + this.contains(events.get(0).getEntity2() ));}catch(NullPointerException e){}
//			for(Event event:events){
//				removeFutureEvent(event);
//				event.resolve(collisionListener);
//				if(event.getEntity1()!=null && !event.getEntity1().isTerminated()){
//					stateChangedObjects.add(event.getEntity1());
//				}
//				if(event.getEntity2()!=null && !event.getEntity2().isTerminated()){
//					stateChangedObjects.add(event.getEntity2());
//				}
//				
//				event.terminate();
//				
//				
//			}
//			
//			for(Entity entity: stateChangedObjects){
//				if(!entity.isTerminated())
//				stateChanged(entity);
//			}
//			dt = dt-(firstEventTime-getEvolvedTime());
//			
//			if(!Util.fuzzyEquals(dt, 0)){
//			evolve(dt, collisionListener);}
//		}
//		else{
//			ArrayList<Entity> stateChangedObjects= new ArrayList<Entity>();
//			for(Entity entity: getAllEntities()){
//				entity.move(dt);
//				if(entity instanceof Ship && ((Ship) entity).isShipThrusterActive()){
//					stateChangedObjects.add(entity);
//				}
//				}
//			addEvolvedTime(dt);
//			for(Entity e:stateChangedObjects){
//				stateChanged(e);
//			}
//			
//			
//		}
//	
//		
//	}
//	public ArrayList<Event> getFirstEventsOf(Entity entity){
//		ArrayList<Entity> entities = new ArrayList<Entity>(getAllEntities());
//		double tc = Double.POSITIVE_INFINITY;
//		double boundaryColTime = Double.POSITIVE_INFINITY;
//		ArrayList<Event> events = new ArrayList<Event>();
//		for(int index = 0; index<entities.size();index++){
//				Entity entity1 = entities.get(index);
//				if(entity1.isTerminated()){System.out.println("WTF!!");}
//				if(!entity.isRelated(entity1)){
//					double time = entity.getTimeToCollision(entity1);
//					if(!Double.isInfinite(time) && Util.fuzzyEquals(time, tc)){
//						events.add(new Event(entity,entity1,time+getEvolvedTime()));
//					}
//					if(time < tc && time >= 0){
//						events.clear();
//						events.add(new Event(entity,entity1,time+getEvolvedTime()));		
//						tc = time;
//					}
//				}
//				}
//			boundaryColTime = entity.getTimeToBoundaryCollision();
//			
//			if(!Double.isInfinite(boundaryColTime) && Util.fuzzyEquals(boundaryColTime, tc)){
//				events.add(new Event(entity,boundaryColTime+getEvolvedTime()));
//			}
//			if(boundaryColTime < tc && boundaryColTime >= 0){
//				events.clear();
//				events.add(new Event(entity,boundaryColTime+getEvolvedTime()));
//			}
//	
//	return events;
//	}

}
